import 'package:flutter/material.dart';
import 'package:universally/universally.dart';

class TextFieldPage extends StatefulWidget {
  const TextFieldPage({super.key});

  @override
  State<TextFieldPage> createState() => _TextFieldPageState();
}

class _TextFieldPageState extends State<TextFieldPage> {
  final controller = OBAddressTextEditingController(text: 'aaaaaaaaaaaaaaaaaa');
  final controller1 = OBAddressTextEditingController(text: 'aaaaaaaaaaaa');
  final controller2 = OBAddressTextEditingController(text: 'aaaa');

  @override
  Widget build(BuildContext context) {
    return BaseScaffold(
      appBarTitleText: 'TextField',
      crossAxisAlignment: CrossAxisAlignment.center,
      padding: EdgeInsets.all(20),
      children: [
        TextField(controller: controller),
        TextField(controller: controller1),
        TextField(controller: controller2),
      ],
    );
  }
}

class OBAddressTextEditingController extends TextEditingController {
  OBAddressTextEditingController({super.text});

  @override
  TextSpan buildTextSpan({
    required BuildContext context,
    TextStyle? style,
    required bool withComposing,
  }) {
    assert(
      !value.composing.isValid || !withComposing || value.isComposingRangeValid,
    );
    final bool composingRegionOutOfRange =
        !value.isComposingRangeValid || !withComposing;
    if (composingRegionOutOfRange) {
      return TextSpan(
        style: style,
        children:
            text.split('').builderIV((i, v) {
              final textLength = text.length;
              bool isBold = isBoldByIndex(textLength, i);
              return TextSpan(text: v, style: isBold ? boldStyle : null);
            }).toList(),
      );
    }
    final TextStyle composingStyle =
        style?.merge(const TextStyle(decoration: TextDecoration.underline)) ??
        const TextStyle(decoration: TextDecoration.underline);
    final textBefore = value.composing.textBefore(value.text);
    final textInside = value.composing.textInside(value.text);
    final textAfter = value.composing.textAfter(value.text);
    final allLength = textBefore.length + textInside.length + textAfter.length;
    return TextSpan(
      style: style,
      children: <TextSpan>[
        TextSpan(
          children: textBefore.split('').builderIV((i, v) {
            bool isBold = isBoldByIndex(allLength, i);
            return TextSpan(text: v, style: isBold ? boldStyle : null);
          }),
        ),
        TextSpan(
          children: textInside.split('').builderIV((i, v) {
            bool isBold = isBoldByIndex(allLength, i + textBefore.length);
            return TextSpan(
              text: v,
              style: composingStyle.merge(isBold ? boldStyle : null),
            );
          }),
        ),
        TextSpan(
          children: textAfter.split('').builderIV((i, v) {
            bool isBold = isBoldByIndex(
              allLength,
              i + textInside.length + textBefore.length,
            );
            return TextSpan(text: v, style: isBold ? boldStyle : null);
          }),
        ),
      ],
    );
  }

  bool isBoldByIndex(int length, int i) =>
      length <= 12 || i < 6 || i >= length - 6;

  TextStyle get boldStyle =>
      TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.red);
}
